package com.broada.apm.filter;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.ApmServer;
import com.broada.apm.common.util.SpringUtils;
import com.broada.apm.logic.ConfigLogic;
import com.broada.apm.logic.impl.ConfigLogicImpl;
import com.broada.apm.utils.DatabaseType;
import com.broada.apm.utils.ExceptionUtils;
import com.google.common.collect.Lists;


@WebFilter
public class DatabaseSetupFilter implements Filter {
    private static final Logger LOG = LoggerFactory.getLogger(DatabaseSetupFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        DataSource ds = SpringUtils.getApplicationContext().getBean(DataSource.class);
        try (Connection conn = ds.getConnection()) {
            String contextPath = filterConfig.getServletContext().getRealPath("/");
            String basepath = "WEB-INF/database/";
            File basedir = new File(contextPath, basepath);
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(basedir,
                    "database.sql")), "utf-8"));
            DatabaseType dataType = SpringUtils.getApplicationContext().getBean(DatabaseType.class);
            try (Statement st = conn.createStatement()) {
            	if(dataType.getDataType().equals("mysql")){
            		st.execute("create table if not exists apm_version( version bigint, descr varchar(200) ) ");
            	}else{
            		ResultSet result = st.executeQuery("select count(*) from dba_tables where table_name = 'APM_VERSION'");
            		while(result.next()){
            			if(result.getInt(1) == 0){
            				st.execute("create table APM_VERSION( version number, descr nvarchar(200)) ");
            			}
            		}
            	}
            }
            int lastversion = -1;
            try (Statement st2 = conn.createStatement()) {
                try (ResultSet rs = st2.executeQuery("select max(version) lastversion from apm_version")) {
                    if (rs.next()) {
                        lastversion = rs.getInt(1);
                    }
                }
            }
            if(lastversion <= 0) lastversion = -1;
            final int lv = lastversion;
            br.lines().forEach(line -> {
                try {
                    String fileprefix = "--file";
                    String trimline = line.trim();
                    trimline.startsWith(fileprefix);
                    String scriptfile = trimline.substring(fileprefix.length()).trim();
                    invokescript(new File(basedir, scriptfile), conn, lv);
                } catch (Exception e) {
                    ExceptionUtils.error(LOG, "初始化数据错误", e);
                }
            });
            
            initL7Module(conn);
            
            br.close();
        } catch (SQLException | IOException e) {
            ExceptionUtils.error(LOG, "初始化数据错误", e);
        }
    }

	private void invokescript(File file, Connection conn, int lastversion) throws IOException {
        String verprefix = "--ver";
        try(BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"))) {
            final AtomicInteger current = new AtomicInteger(0);
            StringBuffer sqlbuffer = new StringBuffer();
            br.lines().forEach(l -> {
                try {
                    String tl = l.trim();
                    if (tl.startsWith(verprefix)) {
                        String verinfo = tl.substring(verprefix.length()).trim();
                        String[] vers = verinfo.split(" ", 2);
                        int currentver = Integer.parseInt(vers[0]);
                        current.set(currentver);
                        if (currentver > lastversion) {
                            updateVersion(conn, currentver, vers[1]);
                        }
                        return;
                    }
                    if (current.get() > lastversion) {
                        sqlbuffer.append(" ").append(tl).append("\n");
                        if (tl.endsWith(";")) {
                            String sql = sqlbuffer.toString();
//                            LOG.info("执行SQL：" + sql);
                            sqlbuffer.delete(0, sqlbuffer.length());
                            if(sql.trim().length() >0 ) {
                                try(Statement st = conn.createStatement()){
                                    st.execute(sql);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    ExceptionUtils.error(LOG, "执行 " + file.getAbsoluteFile() + " 出错", e);
                }
            });
        }
    }

    private void updateVersion(Connection conn, int currentver, String vers) throws SQLException {
        try (PreparedStatement ps = conn.prepareStatement("insert into apm_version (version, descr) values(?,?)")) {
            ps.setInt(1, currentver);
            ps.setString(2, vers);
            ps.execute();
        }
    }
    
    private void initL7Module(Connection conn) {
    	
    	try (Statement st = conn.createStatement()) {
            try (ResultSet rs = st.executeQuery("select count(*) from l7module")) {
                if (rs.next()) {
                    if(rs.getInt(1) < 1) {
                    	List<File> l7moduleFiles = getFileList(ApmServer.MODS_DIR);
                    	ConfigLogic configLogic = new ConfigLogicImpl();
                    	for (File l7moduleFile : l7moduleFiles) {
                    		if ("syncmodule_4.0.0.mod".equals(l7moduleFile.getName())) {
                    			try {
									configLogic.resolveL7Module(l7moduleFile);
								} catch (Exception e) {
									ExceptionUtils.error(LOG, "自动解析 " + l7moduleFile.getAbsoluteFile() + " 出错", e);
								}
                    		}
                    	}
                    	l7moduleFiles.stream().sorted((p1,p2)->{
                    		return p1.getPath().length()-p2.getPath().length();
                    	}).forEach(f->{
                    		try {
                    			if ("http_4.0.5.mod".equals(f.getName())) {
                        			configLogic.resolveL7Module(f);
                    			}
							} catch (Exception e) {
								ExceptionUtils.error(LOG, "自动解析 " + f.getAbsoluteFile() + " 出错", e);
							}
                    	});
                    	try {
//							L7ModuleManager.enabledL7Module("1");
						} catch (Exception e) {}
                    	try {
//							L7ModuleManager.enabledL7Module("80");
						} catch (Exception e) {}
                    }
                }
            }
        } catch (SQLException e) {
			
		}
	}
    
    public List<File> getFileList(String strPath) {
    	List<File> filelist = Lists.newArrayList();
		File dir = new File(strPath);
		File[] files = dir.listFiles();
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				String fileName = files[i].getName();
				if (files[i].isDirectory()) {
					filelist.addAll(getFileList(files[i].getAbsolutePath()));
				} else if (fileName.endsWith("mod")) {
					filelist.add(files[i]);
				} else {
					continue;
				}
			}

		}
		return filelist;
	}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {

    }

    @Override
    public void destroy() {

    }

}
